El notebook de IPython

Python Madrid @Kaleidos (❤) 2014-02-20

Juan Luis Cano (@Pybonacci)

0. ¿Y este quién es?

  • Estudiante de ingeniería aeronáutica
  • Intento de programador autodidacta
  • Usuario de Python desde 2011
  • Divulgación en Pybonacci
  • Cursos: INAEM, próximamente UPV y UPM

1. Brevísima historia de IPython

  • Creado por Fernando Pérez en 2001
  • Inspirado en Mathematica
  • John Hunter ✝ inicia matplotlib a partir de un parche
  • Aparición de la interfaz web en 2011
  • $1.15 M de la fundación Alfred P. Sloan
  • ¡Boom!

Si quieres saber más, no te pierdas nuestra entrevista a Fernando Pérez.

2. Introducción

Intérprete mejorado

Para empezar IPython es un intérprete de Python, pero con superpoderes.


In [1]:
nueva_variable = 42

In [2]:
def nueva_funcion():
    pass

Autocompletado:


In [3]:
#nuev<tab>
nueva_variable


Out[3]:
42

In [4]:
nueva_variable ** 2 / 3


Out[4]:
588.0

Historial:


In [5]:
_3


Out[5]:
42

In [6]:
_4


Out[6]:
588.0

También funciona con objetos:


In [7]:
class Foo(object):
    """Mi clase de prueba."""
    def __init__(self, prop_a=1, prop_b=2):
        self.prop_a = prop_a
        self.prop_b = prop_b

f = Foo()

In [8]:
#f.<tab>
f.prop_a


Out[8]:
1

¡Incluso con el constructor!


In [9]:
#f2 = Foo(prop_<tab>
f2 = Foo(prop_a=1)

Ayuda en línea con un atajo rápido:


In [10]:
Foo?

También acceso al código fuente:


In [11]:
import http.server

In [13]:
http.server??

Arquitectura

Por debajo de todo esto hay mucho más: ¡pasemos a la línea de comandos!

$ ipython console --existing

IPython es toda una infraestructura cliente/servidor. Este notebook es solo un cliente, pero puede haber más: por defecto tenemos la línea de comandos, un cliente Qt y el notebook.

_

(Fuente: http://ipython.org/ipython-doc/dev/development/messaging.html)

...¡Incluso hay cliente para emacs!

3. La interfaz notebook

No es más que otro cliente, pero un cliente muy especial. Para empezar, está organizado en celdas multilínea, que se pueden mover, copiar, pegar y eliminar.


In [17]:
nueva_variable


Out[17]:
38

In [16]:
nueva_variable = 38
nueva_variable


Out[16]:
38

Y las celdas no tienen por qué contener solamente código: pueden contener Markdown arbitrario y podemos definir encabezados. Exactamente lo que estás viendo en este notebook.

$$M = E + e \sin(E)$$

¡Incluso ecuaciones!

La versión 2.0 está en desarrollo en el momento de escribir esta charla, pero es la que he usado:


In [18]:
import IPython
print(IPython.sys_info())


{'codename': 'Work in Progress',
 'commit_hash': 'dd7a5af',
 'commit_source': 'installation',
 'default_encoding': 'UTF-8',
 'ipython_path': '/home/juanlu/Development/Python/pybonacci/charla_ipython/lib/python3.3/site-packages/IPython',
 'ipython_version': '2.0.0-dev',
 'os_name': 'posix',
 'platform': 'Linux-3.12.9-2-ARCH-x86_64-with-arch-Arch-Linux',
 'sys_executable': '/home/juanlu/Development/Python/pybonacci/charla_ipython/bin/python',
 'sys_platform': 'linux',
 'sys_version': '3.3.4 (default, Feb 11 2014, 15:56:08) \n[GCC 4.8.2 20140206 (prerelease)]'}

Introduce varias novedades, como por ejemplo una interfaz modal (http://nbviewer.ipython.org/github/ipython/ipython/blob/master/examples/notebooks/User%20Interface.ipynb), lo que hace que los atajos de teclado sean mucho más efectivos.

Gráficas con matplotlib

Para pintar gráficas con matplotlib lo mejor es activar el modo inline, que las incrusta en el mismo notebook


In [1]:
%matplotlib inline

In [2]:
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 5)
plt.plot(x, np.sin(x) * np.cos(3 * x))
plt.show()


Formato de los notebooks

Los notebooks en realidad no son más que documentos JSON:


In [3]:
!cat "Charla IPython.ipynb"


{
 "metadata": {
  "name": "",
  "signature": "sha256:0cb528f0918d4fd57740b4f150f649ee3c61141a97e3c98b89befb1ca7b29900"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "El notebook de IPython"
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Python Madrid @Kaleidos (\u2764) 2014-02-20"
     ]
    },
    {
     "cell_type": "heading",
     "level": 4,
     "metadata": {},
     "source": [
      "Juan Luis Cano (@Pybonacci)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# 0. \u00bfY este qui\u00e9n es?\n",
      "\n",
      "* Estudiante de ingenier\u00eda aeron\u00e1utica\n",
      "* Intento de programador autodidacta\n",
      "* Usuario de Python desde 2011\n",
      "* Divulgaci\u00f3n en Pybonacci\n",
      "* Cursos: INAEM, pr\u00f3ximamente UPV y UPM"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# 1. Brev\u00edsima historia de IPython\n",
      "\n",
      "* Creado por Fernando P\u00e9rez en 2001\n",
      "* Inspirado en Mathematica\n",
      "* John Hunter \u271d inicia matplotlib a partir de un parche\n",
      "* Aparici\u00f3n de la interfaz web en 2011\n",
      "* $1.15 M de la fundaci\u00f3n Alfred P. Sloan\n",
      "* **\u00a1Boom!**"
     ]
    },
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "2. Introducci\u00f3n"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Int\u00e9rprete mejorado"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Para empezar IPython es un int\u00e9rprete de Python, pero con superpoderes."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nueva_variable = 42"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def nueva_funcion():\n",
      "    pass"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Autocompletado:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#nuev<tab>\n",
      "nueva_variable"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 3,
       "text": [
        "42"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nueva_variable ** 2 / 3"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 4,
       "text": [
        "588.0"
       ]
      }
     ],
     "prompt_number": 4
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Historial:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "_3"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 5,
       "text": [
        "42"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "_4"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 6,
       "text": [
        "588.0"
       ]
      }
     ],
     "prompt_number": 6
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Tambi\u00e9n funciona con objetos:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "class Foo(object):\n",
      "    \"\"\"Mi clase de prueba.\"\"\"\n",
      "    def __init__(self, prop_a=1, prop_b=2):\n",
      "        self.prop_a = prop_a\n",
      "        self.prop_b = prop_b\n",
      "\n",
      "f = Foo()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 7
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#f.<tab>\n",
      "f.prop_a"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 8,
       "text": [
        "1"
       ]
      }
     ],
     "prompt_number": 8
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "\u00a1Incluso con el constructor!"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#f2 = Foo(prop_<tab>\n",
      "f2 = Foo(prop_b=3)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 9
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Ayuda en l\u00ednea con un atajo r\u00e1pido:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "Foo?"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 10
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Tambi\u00e9n acceso al c\u00f3digo fuente:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import http.server"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 11
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "http.server??"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 12
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Arquitectura"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Por debajo de todo esto hay mucho m\u00e1s: \u00a1pasemos a la l\u00ednea de comandos!\n",
      "\n",
      "`$ ipython console --existing`"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "IPython es toda una infraestructura cliente/servidor. Este notebook es solo un cliente, pero puede haber m\u00e1s: por defecto tenemos la l\u00ednea de comandos, un cliente Qt y el notebook.\n",
      "\n",
      "![Frontend kernel](files/frontend-kernel_small.png)\n",
      "\n",
      "_\n",
      "<div class=\"alert alert-info\">(Fuente: http://ipython.org/ipython-doc/dev/development/messaging.html)</div>"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "...\u00a1Incluso hay cliente para emacs!\n",
      "\n",
      "![Cliente emacs](/files/ipython_emacs.png)"
     ]
    },
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "3. La interfaz notebook"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "No es m\u00e1s que otro cliente, pero un cliente muy especial. Para empezar, est\u00e1 organizado en **celdas multil\u00ednea**, que se pueden mover, copiar, pegar y eliminar."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nueva_variable"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 16,
       "text": [
        "38"
       ]
      }
     ],
     "prompt_number": 16
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nueva_variable = 38\n",
      "nueva_variable"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 15,
       "text": [
        "38"
       ]
      }
     ],
     "prompt_number": 15
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Y las celdas no tienen por qu\u00e9 contener solamente c\u00f3digo: pueden contener Markdown arbitrario y podemos definir encabezados. *Exactamente lo que est\u00e1s viendo en este notebook*."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "La versi\u00f3n 2.0 est\u00e1 en desarrollo en el momento de escribir esta charla, pero es la que he usado:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import IPython\n",
      "print(IPython.sys_info())"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "{'codename': 'Work in Progress',\n",
        " 'commit_hash': 'dd7a5af',\n",
        " 'commit_source': 'installation',\n",
        " 'default_encoding': 'UTF-8',\n",
        " 'ipython_path': '/home/juanlu/Development/Python/pybonacci/charla_ipython/lib/python3.3/site-packages/IPython',\n",
        " 'ipython_version': '2.0.0-dev',\n",
        " 'os_name': 'posix',\n",
        " 'platform': 'Linux-3.12.9-2-ARCH-x86_64-with-arch-Arch-Linux',\n",
        " 'sys_executable': '/home/juanlu/Development/Python/pybonacci/charla_ipython/bin/python',\n",
        " 'sys_platform': 'linux',\n",
        " 'sys_version': '3.3.4 (default, Feb 11 2014, 15:56:08) \\n[GCC 4.8.2 20140206 (prerelease)]'}\n"
       ]
      }
     ],
     "prompt_number": 18
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Introduce varias novedades, como por ejemplo una **interfaz modal** (http://nbviewer.ipython.org/github/ipython/ipython/blob/master/examples/notebooks/User%20Interface.ipynb), lo que hace que los atajos de teclado sean mucho m\u00e1s efectivos."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Gr\u00e1ficas con matplotlib"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Para pintar gr\u00e1ficas con matplotlib lo mejor es activar el modo `inline`, que las incrusta en el mismo notebook"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%matplotlib inline"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import numpy as np\n",
      "import matplotlib.pyplot as plt\n",
      "\n",
      "x = np.linspace(0, 5)\n",
      "plt.plot(x, np.sin(x) * np.cos(3 * x))\n",
      "plt.show()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\nEEIIIcbx/wEkMyZb56GFwwAAAABJRU5ErkJggg==\n",
       "text": [
        "<matplotlib.figure.Figure at 0x7f804006c550>"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Formato de los notebooks"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "3. Publicaci\u00f3n\n",
      "\n",
      "  * Documento JSON\n",
      "  * Exportaci\u00f3n a otros formatos\n",
      "  * nbviewer\n",
      "\n",
      "4. Widgets interactivos\n",
      "\n",
      "5. Futuro\n",
      "\n",
      "  * https://github.com/ipython/ipython/wiki/Roadmap:-IPython\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}
¿Había comentado que puedo ejecutar comandos de consola desde el notebook?

Estos notebooks se pueden exportar a otros formatos (http://ipython.org/ipython-doc/dev/interactive/nbconvert.html).


In [3]:
!ipython nbconvert --to html "Charla IPython.ipynb"


[NbConvertApp] Using existing profile dir: '/home/juanlu/.ipython/profile_default'
[NbConvertApp] Converting notebook Charla IPython.ipynb to html
[NbConvertApp] Support files will be in Charla IPython_files/
[NbConvertApp] Loaded template full.tpl
/home/juanlu/Development/Python/pybonacci/charla_ipython/lib/python3.3/site-packages/IPython/nbconvert/utils/pandoc.py:63: RuntimeWarning: You are using an old version of pandoc (1.11.1)
Recommended version is 1.12.1.
Try updating.http://johnmacfarlane.net/pandoc/installing.html.
Continuing with doubts...
  check_pandoc_version()
[NbConvertApp] Writing 258400 bytes to Charla IPython.html

4. Widgets interactivos

5. Futuro

La financiación alcanza hasta el año 2014. Hasta entonces, los planes del equipo de desarollo de IPython están aquí:

https://github.com/ipython/ipython/wiki/Roadmap:-IPython

Objetivo:

Un servidor de Notebook de IPython sólido y multiusuario con widgets interactivos y utilidades potentes para interactuar con otros formatos, como Sphinx / HTML o documentos LaTeX / PDF, capaz de ejecutar código en varios lenguajes (Python, Ruby, R, etc.)

¿Impacientes? :)

¡Muchas gracias!